package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.message.domain.entity.PushSetEntity;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.domain.entity.PaasMenuEntity;
import com.xbongbong.paas.domain.entity.ext.OptionalRangeEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.OptionalRangeEnum;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasMenuModel;
import com.xbongbong.paas.pojo.ClueRulePojo;
import com.xbongbong.paas.pojo.ClueRuleTypePojo;
import com.xbongbong.paas.pojo.CustomerUserPojo;
import com.xbongbong.paas.pojo.LeadOrFrePojo;
import com.xbongbong.paas.pojo.PublicRuleItemListPojo;
import com.xbongbong.paas.pojo.PublicRuleLabelPojo;
import com.xbongbong.paas.pojo.RestrictPojo;
import com.xbongbong.paas.pojo.RuleSavePojo;
import com.xbongbong.paas.pojo.dto.ClueRuleDetaiDTO;
import com.xbongbong.paas.pojo.dto.ClueRuleSaveDTO;
import com.xbongbong.paas.pojo.dto.CustomerRuleSaveRemindTimeDTO;
import com.xbongbong.paas.pojo.dto.CustomerRuleUserListDTO;
import com.xbongbong.paas.pojo.dto.ReturnCustomer2PublicAsyncDTO;
import com.xbongbong.paas.pojo.vo.ClueListRuleVO;
import com.xbongbong.paas.pojo.vo.ClueRuleDetailVO;
import com.xbongbong.paas.pojo.vo.CustomerRuleRemindTimeVO;
import com.xbongbong.paas.pojo.vo.CustomerRuleUserListVO;
import com.xbongbong.paas.pojo.vo.PublicRuleItemListVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.ClueRuleService;
import com.xbongbong.paas.service.TemplateService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.LabelEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.UpdateCustomerTeamScenesEnum;
import com.xbongbong.pro.enums.errorcodes.PublicPoolErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.message.constant.ClueBackPushConstant;
import com.xbongbong.pro.message.enums.PushObjectTypeEnum;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.model.PushSetModel;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.message.pushset.CluePushSet;
import com.xbongbong.pro.message.service.MessageService;
import com.xbongbong.pro.template.pojo.EnablePojo;
import com.xbongbong.pro.template.pojo.dto.TemplateDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ClueRuleEntity;
import com.xbongbong.saas.domain.entity.RuleClueEntity;
import com.xbongbong.saas.domain.entity.TagEntity;
import com.xbongbong.saas.domain.entity.TagLinkEntity;
import com.xbongbong.saas.domain.entity.ext.ClueEntityExt;
import com.xbongbong.saas.enums.ChildClueRuleEnum;
import com.xbongbong.saas.enums.ClueChildTypeEnum;
import com.xbongbong.saas.enums.ClueRuleEnum;
import com.xbongbong.saas.enums.ClueSeniorRuleTypeEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.TagTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.enums.dictionary.ClueStatusEnum;
import com.xbongbong.saas.factory.publicrule.CheckClueRuleFactory;
import com.xbongbong.saas.factory.publicrule.CheckClueRuleGainRate;
import com.xbongbong.saas.factory.publicrule.ICheckClueRule;
import com.xbongbong.saas.factory.publicrule.IOperateClueRuleValue;
import com.xbongbong.saas.factory.publicrule.OperateClueRuleValueFactory;
import com.xbongbong.saas.factory.publicrule.OperateMaxClueNumRuleValue;
import com.xbongbong.saas.help.MarketManagementBusinessHelp;
import com.xbongbong.saas.help.PublicSeniorRuleHelp;
import com.xbongbong.saas.model.ClueModel;
import com.xbongbong.saas.model.ClueRuleModel;
import com.xbongbong.saas.model.ClueUserModel;
import com.xbongbong.saas.model.LabelModel;
import com.xbongbong.saas.model.TagLinkModel;
import com.xbongbong.saas.model.TagModel;
import com.xbongbong.saas.service.ClueUserService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.RoleEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.help.SysEnvHelp;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.RoleModel;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;


/**o
 * @author long
 * @version v1.0
 * @date 2020/12/1 10:17
 * @since v1.0
 */
@Service("clueRuleService")
public class ClueRuleServiceImpl implements ClueRuleService {

    private static final Logger LOG = LoggerFactory.getLogger(ClueRuleServiceImpl.class);

    @Resource
    private ClueRuleModel clueRuleModel;
    @Resource
    private UserModel userModel;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private PushSetModel pushSetModel;
    @Resource
    private TagLinkModel tagLinkModel;
    @Resource
    private TagModel tagModel;
    @Resource
    private ClueModel clueModel;
    @Resource
    private CheckClueRuleFactory checkClueRuleFactory;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private MessageService messageService;
    @Resource
    private ClueUserModel clueUserModel;
    @Resource
    private ClueUserService clueUserService;
    @Resource
    @Lazy
    private UserTeamService userTeamService;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private RoleModel roleModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private LabelModel labelModel;
    @Lazy
    @Resource
    private TemplateService templateService;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PackageHelp packageHelp;
    @Resource
    private PaasMenuModel paasMenuModel;
    @Resource
    private MarketManagementBusinessHelp marketManagementBusinessHelp;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private PublicSeniorRuleHelp publicSeniorRuleHelp;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private SysEnvHelp sysEnvHelp;
    /**
     * 【web】规则列表
     *
     * @param baseDTO 获取规则入参
     * @return ClueListRuleVO
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<ClueListRuleVO> getClueRuleList(BaseDTO baseDTO) throws XbbException {

        ClueListRuleVO clueListRuleVO = new ClueListRuleVO();
        Map<String, Object> param = new HashMap<>(4);
        param.put("corpid", baseDTO.getCorpid());
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("start", 0);
        param.put("pageNum", 10);
        List<ClueRuleEntity> ruleList = clueRuleModel.findEntitys(param);
        Map<Integer, ClueRuleEntity> ruleMap = new HashMap<>(10);
        for (ClueRuleEntity rule : ruleList) {
            ruleMap.put(rule.getRuleType(), rule);
        }

        List<ClueRuleEnum> enumList = ClueRuleEnum.getAllEnum();

        List<ClueRulePojo> rulePojos = new ArrayList<>();
        for (ClueRuleEnum ruleEnum : enumList) {
            ClueRulePojo clueRulePojo = new ClueRulePojo();
            Integer ruleType = ruleEnum.getCode();
            String typeName = ruleEnum.getName();
            String tip = ruleEnum.getTip();
            Integer status = 0;
            ClueRuleEntity rule = ruleMap.get(ruleType);
            if (rule != null) {
                status = rule.getStatus();
            }
            clueRulePojo.setTypeName(typeName);
            clueRulePojo.setTip(tip);
            clueRulePojo.setStatus(status);
            clueRulePojo.setRuleType(ruleType);

            rulePojos.add(clueRulePojo);
        }
        clueListRuleVO.setClueRuleList(rulePojos);
        TemplateDTO templateDTO = new TemplateDTO();
        BeanUtil.copyProperties(baseDTO, templateDTO);
        templateDTO.setSubBusinessType(XbbRefTypeEnum.CLUE.getCode());
        templateDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
        List<EnablePojo> saasTemplateList = templateService.getSaasTemplateList(templateDTO);
        clueListRuleVO.setFormList(saasTemplateList);

        return new XbbResponse<>(clueListRuleVO);
    }

    /**
     * 【web】规则详情
     *
     * @param clueRuleDetailDTO 获取规则详情入参
     * @return ClueRuleDetailVO
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<ClueRuleDetailVO> getClueRuleDetail(ClueRuleDetaiDTO clueRuleDetailDTO) throws XbbException {
        String corpid = clueRuleDetailDTO.getCorpid();
        Integer ruleType = clueRuleDetailDTO.getRuleType();

        ClueRuleDetailVO ruleDetailVO;
        try {
            ruleDetailVO = detail(ruleType, corpid);
        } catch (XbbException e) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        ruleDetailVO.setChildTypeArray(getChildTypeList(ruleType));

        // 数据字典项：获取线索状态
        ruleDetailVO.setStatusArray(ClueStatusEnum.getCodeAndNameMap());

        return new XbbResponse<>(ruleDetailVO);
    }

    /**
     * 【web】保存规则
     *
     * @param clueRuleSaveDTO 保存规则入参
     * @return Integer
     * @throws XbbException 业务异常
     * @version v1.0
     * @since v1.0
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public XbbResponse<Integer> save(ClueRuleSaveDTO clueRuleSaveDTO) throws XbbException {
        String corpid = clueRuleSaveDTO.getCorpid();
        ClueRuleEntity oldEntity = clueRuleModel.getByRuleType(clueRuleSaveDTO.getRuleType(), corpid);
        Integer clueRuleId = save(corpid, clueRuleSaveDTO);
        ClueRuleEntity newEntity = clueRuleModel.getByRuleType(clueRuleSaveDTO.getRuleType(), corpid);
        try {
            saveLog(corpid, oldEntity, newEntity, clueRuleSaveDTO);
        } catch (Exception e) {
            LOG.error("日志保存错误");
        }
        return new XbbResponse<>(clueRuleId);
    }

    /**
     * 【web】保存公海池退回提醒时间
     *
     * @param clueRuleSaveRemindTimeDTO 保存公海池退回提醒时间入参
     * @return Integer
     * @throws XbbException 业务异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public XbbResponse<Integer> saveRemindTime(CustomerRuleSaveRemindTimeDTO clueRuleSaveRemindTimeDTO) throws XbbException {
        String corpid = clueRuleSaveRemindTimeDTO.getCorpid();
        String usedId = clueRuleSaveRemindTimeDTO.getUserId();
        // 登录用户
        String loginUserName = clueRuleSaveRemindTimeDTO.getLoginUserName();
        Integer saveRemindTimeId;
        try {
            saveRemindTimeId = saveRemindTime(corpid, clueRuleSaveRemindTimeDTO.getDay());
        } catch (XbbException e) {
            LOG.error("保存公海池线索退回提醒时间失败");
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218002);
        }

        // 日志
        CompanyConfigEntity companyConfig = companyConfigModel.initConfigEntity(corpid, CompanyConfigEnum.CLUE_PUBLIC_RULE_REMIND_TIME.getAlias());
        String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_SET_BACK_TIME_CUSTOMER_RULE), companyConfig.getConfigName(), companyConfig.getConfigValue());
        mongoLogHelp.buildLog(corpid, usedId, loginUserName, OperateModuleTypeEnum.OpenSeaRules, OperateTypeEnum.SET, companyConfig.getId().toString(), companyConfig.getConfigName(), memo, clueRuleSaveRemindTimeDTO.getHttpHeader());
        return new XbbResponse<>(saveRemindTimeId);
    }

    /**
     * 【web】获取公海池退回提醒时间
     *
     * @param baseDTO 获取公海池退回提醒时间入参
     * @return Integer
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CustomerRuleRemindTimeVO> getRemindTime(BaseDTO baseDTO) throws XbbException {
        String corpid = baseDTO.getCorpid();
        Integer remindTime = Integer.valueOf(CompanyConfigEnum.CLUE_PUBLIC_RULE_REMIND_TIME.getValue());
        try {
            CompanyConfigEntity companyConfig = companyConfigModel.initConfigEntity(corpid,
                    CompanyConfigEnum.CLUE_PUBLIC_RULE_REMIND_TIME.getAlias());
            if (companyConfig != null) {
                remindTime = StringUtil.toInt(companyConfig.getConfigValue(), remindTime);
            }
        } catch (Exception e) {
            LOG.error("getRemindTime异常，corpid=" + corpid, e);
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218003);
        }
        CustomerRuleRemindTimeVO clueRuleRemindTimeVO = new CustomerRuleRemindTimeVO();
        clueRuleRemindTimeVO.setBackDay(remindTime);
        return new XbbResponse<>(clueRuleRemindTimeVO);
    }

    /**
     * 单公司跟进公海规则退回公海
     * @param corpid 公司id
     * @param back false不需要退回公海池   true退回公海池
     * @param notify false不需要即将退回提醒   true即将退回提醒
     */
    private void backToPublic(String corpid, boolean notify, boolean back) {
        LOG.info("returnClue_start:" + corpid);
        try {

            Boolean standardWithFeeType = marketManagementBusinessHelp.isStandardWithFeeType(corpid);
            if (standardWithFeeType) {
                LOG.info("该公司是标准版，不执行线索退回公海池脚本:corpid=====" + corpid);
                return;
            }

            boolean enableWithApp = marketManagementBusinessHelp.isEnableWithApp(corpid);
            if (!enableWithApp) {
                LOG.info("该公司的线索应用未开启，不执行线索退回公海池脚本:corpid=====" + corpid);
                return;
            }

            PaasMenuEntity byAlias = paasMenuModel.getByAlias(XbbRefTypeEnum.CLUE.getAlias(), corpid);
            if (Objects.isNull(byAlias) || !Objects.equals(byAlias.getEnable(), BasicConstant.ONE)) {
                LOG.info("该公司的线索菜单未开启，不执行线索退回公海池脚本:corpid=====" + corpid);
                return;
            }

            //推送规则，此处规则现在只有是否推送给主负责人
            boolean isPushMain = getIsPushMain(corpid);

            // 开启推送，将更新标签（删除该公司的所有退回公海池标签）
            if (notify) {
                tagLinkModel.deleteReturnPublicTags(corpid, TagTypeEnum.PUBLIC_CLUE_RULE.getCode());
            }


            //获取公司所有的相关公海规则   无新建跟进线索规则  无新建机会线索规则  无新建合同线索规则 最大拥有线索数规则
            List<ClueRuleEntity> ruleList = getRuleRelatedScript(corpid);

            //获取提醒时间配置
            Integer advanceTime = getRemindTime(corpid);

            Map<String, Object> userParam = new HashMap<>(5);
            userParam.put("corpid", corpid);
            //若是将异常的del状态的一起跑，会有很多user被跑到（前三家是近四万---近九万）
            userParam.put("del", 0);
            //一页100
            Integer pagerNum = 100;
            // 当前公司的用户总数
            Integer userCount = userModel.getEntitysCount(userParam);
            //总页数
            Integer pageTotal = userCount / pagerNum;
            //不能整除，页码加1
            if (userCount % pagerNum > 0) {
                ++pageTotal;
            }
            for (int page = 0; page < pageTotal; page++) {
                Integer start = page * pagerNum;
                userParam.put("start", start);
                userParam.put("pageNum", pagerNum);
                userParam.put("columns", "corpid,user_id,name,role_ids,department");
                List<UserEntity> users = userModel.findEntitys(userParam);
                for (UserEntity user : users) {

                    //当前员工负责线索数大于1万跳过处理

                    Map<String, Object> countParam = new HashMap<>();
                    countParam.put("corpid", corpid);
                    countParam.put("isMain", 1);
                    countParam.put("userId", user.getUserId());
                    countParam.put("del", 0);
                    Integer count = clueUserModel.getEntitysCount(countParam);
                    if (count > 10000) {
                        LOG.error("coount > 10000,corpid:" + corpid + "userId:" + user.getUserId());
                        continue;
                    }

                    for (ClueRuleEntity rule : ruleList) {
                        //执行完一条规则，员工拥有的线索可能会发生变化
                        Integer ruleType = rule.getRuleType();
                        //最大线索数逻辑不能用分页处理区分处理
                        if (!Objects.equals(ruleType, ClueRuleEnum.MAX_CLUE_NUM_RULE.getCode())) {
                            backToPublic4NotMaxCount(corpid, user, back, notify, rule, advanceTime, isPushMain);
                        } else {
                            //最大线索数规则没有好的方案 还是以原来的方案处理
                            backToPublic4MaxCount(corpid, user, back, notify, rule, advanceTime, isPushMain);
                        }

                    }
                }
            }
            //一个公司操作完成，移除已打标签线索缓存
            paasRedisHelper.removeValue(RedisPrefixConstant.TAG_LINK_CLUE_ID, corpid);
        } catch (Exception e) {
            LOG.error("ClueRuleServiceImpl.backToPublic中出现了奇怪的异常, corpid:" + corpid, e);
        }
    }

    /**
     * 非最大线索数退回公海池（员工逻辑）
     * @param corpid
     * @param user
     * @param back
     * @param notify
     * @param rule
     * @param advanceTime
     * @param isPushMain
     */
    private void backToPublic4NotMaxCount(String corpid, UserEntity user, boolean back, boolean notify,
                                          ClueRuleEntity rule, Integer advanceTime, boolean isPushMain){

        Integer ruleType = rule.getRuleType();
        ICheckClueRule checkRule = null;
        try {
            checkRule = checkClueRuleFactory.checkClueRuleFactory(ruleType);
        } catch (XbbException e) {
            LOG.error("corpid:" + corpid, e);
            return ;
        }

        //执行完一条规则，员工拥有的线索可能会发生变化，不能用page的分页
        Long startId = 0L;
        Integer pageNum = 1000;

        List<Long> idIn = clueUserModel.getDataIdList4Rule(corpid, 1, user.getUserId(), startId, pageNum);

        while (idIn.size() > 0){
            List<RuleClueEntity> clueList = null;
            try {
                clueList = clueModel.getMainClueList4Rule(corpid, idIn);
            } catch (Exception e) {
                LOG.error("clueModel.getMainClueList4Rule error corpid:" + corpid + " idIn:" + idIn);
            }

            List<RuleClueEntity> backClueList = null;
            if(back){
                try {
                    backClueList = checkRule.getBackClueList(user, rule, clueList);
                } catch (XbbException e) {
                    LOG.error("corpid:" + corpid + "ruleType:" + ruleType, e);
                    continue;
                }
                if (backClueList != null && backClueList.size() > 0) {
                    return2Public(user, backClueList, rule.getRuleType());
                    pushReturnMessage(user, backClueList, rule.getRuleType());
                }
            }

            if(notify){
                List<RuleClueEntity> notifyClueList = null;
                remove(clueList, backClueList);
                try {
                    notifyClueList = checkRule.getBackClueList(user, rule, clueList, advanceTime);
                } catch (XbbException e) {
                    LOG.error("XbbParamException_corpid:" + corpid + "ruleType:" + rule.getRuleType(), e);
                    continue;
                } catch (Exception e1) {
                    LOG.error("Exception_corpid:" + corpid + "ruleType:" + rule.getRuleType(), e1);
                    continue;
                }

                if (notifyClueList != null && notifyClueList.size() > 0) {

                    tagReturnPublic(user, notifyClueList);
                    if (isPushMain) {
                        pushTagMessage(user, notifyClueList, advanceTime);

                    }

                }
            }

            //最后的一个id作为起始id
            startId = idIn.get(idIn.size() - 1);
            idIn = clueUserModel.getDataIdList4Rule(corpid, 1, user.getUserId(), startId, pageNum);
        }
    }

    /**
     * 最大线索数退回公海池（员工逻辑）
     * @param corpid
     * @param user
     * @param back
     * @param notify
     * @param rule
     * @param advanceTime
     * @param isPushMain
     */
    private void backToPublic4MaxCount(String corpid, UserEntity user, boolean back, boolean notify,
                                       ClueRuleEntity rule, Integer advanceTime, boolean isPushMain) throws XbbException {
        List<RuleClueEntity> clueList = clueModel.getMainClueListByUserId(corpid, user.getUserId(), null, null, null, null, null, null);
        Integer ruleType = rule.getRuleType();
        ICheckClueRule checkRule = null;
        try {
            checkRule = checkClueRuleFactory.checkClueRuleFactory(ruleType);
        } catch (XbbException e) {
            LOG.error("corpid:" + corpid, e);
            return ;
        }
        List<RuleClueEntity> backClueList = null;
        if(back){
            try {
                backClueList = checkRule.getBackClueList(user, rule, clueList);
            } catch (XbbException e) {
                LOG.error("corpid:" + corpid + "ruleType:" + ruleType, e);
                return ;
            }
            if (backClueList != null && backClueList.size() > 0) {
                return2Public(user, backClueList, rule.getRuleType());
                pushReturnMessage(user, backClueList, rule.getRuleType());
            }
        }

        if(notify){
            List<RuleClueEntity> notifyClueList = null;
            remove(clueList, backClueList);
            try {
                notifyClueList = checkRule.getBackClueList(user, rule, clueList, advanceTime);
            } catch (XbbException e) {
                LOG.error("XbbParamException_corpid:" + corpid + "ruleType:" + rule.getRuleType(), e);
                return ;
            } catch (Exception e1) {
                LOG.error("Exception_corpid:" + corpid + "ruleType:" + rule.getRuleType(), e1);
                return ;
            }
            if (notifyClueList != null && notifyClueList.size() > 0) {
                tagReturnPublic(user, notifyClueList);
                if (isPushMain) {
                    pushTagMessage(user, notifyClueList, advanceTime);
                }
            }
        }
    }


    @Override
    public Integer canGainClue(String corpid, UserEntity userEntity, Long clueId, List<ClueRuleEntity> ruleList, int dataIdSize) throws XbbException {
        for (ClueRuleEntity rule : ruleList) {
            ICheckClueRule checkRule = checkClueRuleFactory.checkClueRuleFactory(rule.getRuleType());
            boolean flag = checkRule.canGainClue(rule, corpid, userEntity, clueId, dataIdSize, null);
            //只要有一个规则不允许获取线索就不允许
            if (!flag) {
                return rule.getRuleType();
            }
        }
        return 0;
    }

    @Override
    public PublicRuleItemListVO clueItemList(BaseDTO baseDTO) throws XbbException {
        PublicRuleItemListVO setListVO = new PublicRuleItemListVO();
        List<PublicRuleItemListPojo> ruleSetItem = new ArrayList<>();
        PaasAppEntity marketManagementApp = paasAppModel.getByAlias(XbbRefTypeEnum.MARKET_MANAGEMENT.getAlias(), baseDTO.getCorpid());
        Boolean standardWithFeeType = packageHelp.isStandardWithFeeType(baseDTO.getCorpid());
        if (Objects.nonNull(marketManagementApp) && Objects.equals(marketManagementApp.getEnable(), BasicConstant.ONE) && !standardWithFeeType) {
            // 线索应用关闭是没有这个线索公海池设置
            PublicRuleItemListPojo cluePojo = new PublicRuleItemListPojo();
            cluePojo.setAlias("clueRuleSet");
            cluePojo.setBusinessType(XbbRefTypeEnum.CLUE.getCode());
            cluePojo.setName(I18nMessageUtil.getMessage(StringConstant.CLUE_PUBLIC_RULE_SET));
            ruleSetItem.add(cluePojo);
        }
        PublicRuleItemListPojo customerPojo = new PublicRuleItemListPojo();
        customerPojo.setAlias("customerRuleSet");
        customerPojo.setBusinessType(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
        customerPojo.setName(I18nMessageUtil.getMessage(StringConstant.CUSTOMER_PUBLIC_RULE_SET));
        ruleSetItem.add(customerPojo);
        setListVO.setList(ruleSetItem);
        return setListVO;
    }

    @Override
    public void updateGainRateToRedis(String corpid,
                                      UserEntity userEntity) throws XbbException{
        String userId = userEntity.getUserId();
        //获取用户的每天的捞取、分配频次
        Integer num = StringUtil.toInt(paasRedisHelper.getValue(RedisPrefixConstant.CLUE_GAIN_RATE, corpid + "_" + userId), null);
        if(num == null){
            try {
                //兼容老逻辑
                ClueRuleEntity rule = null;
                if (commonHelp.isCustomerPublicPoolSeniorModel(corpid)){
                    rule = publicSeniorRuleHelp.getClueRule(corpid, ClueSeniorRuleTypeEnum.GAIN_RATE_RULE.getCode(),
                            XbbRefTypeEnum.CLUE.getCode());
                }else {
                    rule = clueRuleModel.getByRuleType(ClueRuleEnum.GAIN_RATE_RULE.getCode(), corpid);
                }
                if (Objects.isNull(rule)){
                    return;
                }
                ICheckClueRule checkRule = checkClueRuleFactory.checkClueRuleFactory(rule.getRuleType());
                CheckClueRuleGainRate checkRuleGainRate = (CheckClueRuleGainRate)checkRule;
                num = checkRuleGainRate.getClueGainRateFromDB(rule, userEntity);
            } catch (XbbException e) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
            }
        }
        if(num != null){
            num --;
            Long endTime = DateTimeUtil.getTodayInt()+86400L;
            Long now = DateTimeUtil.getInt();
            Long time = endTime - now;
            paasRedisHelper.setValue(RedisPrefixConstant.CLUE_GAIN_RATE, corpid + "_" + userId, num, time.intValue());
        }
    }

    @Override
    public void updateGainRateByIds(String corpid,
                                    UserEntity userEntity, List<Long> ids) throws XbbException{
        //兼容老逻辑
        ClueRuleEntity rule = null;
        if (commonHelp.isCustomerPublicPoolSeniorModel(corpid)){
            rule = publicSeniorRuleHelp.getClueRule(corpid, ClueSeniorRuleTypeEnum.GAIN_RATE_RULE.getCode(),
                    XbbRefTypeEnum.CLUE.getCode());
        }else {
            rule = clueRuleModel.getByRuleType(ClueRuleEnum.GAIN_RATE_RULE.getCode(), corpid);
        }
        String userId = userEntity.getUserId();
        //获取用户的每天的捞取、分配频次
        Integer num = StringUtil.toInt(paasRedisHelper.getValue(RedisPrefixConstant.CLUE_GAIN_RATE, corpid + "_" + userId), null);
        if(num == null){
            try {
                if (Objects.isNull(rule)){
                    return;
                }
                ICheckClueRule checkRule = checkClueRuleFactory.checkClueRuleFactory(rule.getRuleType());
                CheckClueRuleGainRate checkRuleGainRate = (CheckClueRuleGainRate)checkRule;
                num = checkRuleGainRate.getClueGainRateFromDB(rule, userEntity);
            } catch (XbbException e) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
            }
        }
        if(num != null){
            Integer idSize = ids.size();
            num -= idSize;
            Long endTime = DateTimeUtil.getTodayInt()+86400L;
            Long now = DateTimeUtil.getInt();
            Long time = endTime - now;
            paasRedisHelper.setValue(RedisPrefixConstant.CLUE_GAIN_RATE, corpid + "_" + userId, num, time.intValue());
        }
    }

    @Async(value = "deletePublicTagThreadPool")
    @Override
    public void deletePublicTag(String corpid, List<Long> clueIds) throws XbbException {
        LOG.info("deletePublicTag start corpid:" + corpid + " clueIds:" + clueIds);
        try {
            // TODO: 2022/9/19 改成队列延时
            Thread.sleep(500);
        } catch (InterruptedException e) {
            LOG.error("Thread.sleep", e);
            // 恢复中断状态
            Thread.currentThread().interrupt();
        }

        try {
            List<RuleClueEntity> clueList = formatRuleClue(clueModel.getByKeys(clueIds, corpid));
            List<UserEntity> userList = clueUserService.getMainUserList(clueIds, corpid, 1);
            //获取公司所有的相关公海规则   无新建跟进线索规则  无新建机会线索规则  无新建合同线索规则
            List<Integer> ruleTypeIn =  new ArrayList<>();
            ruleTypeIn.add(ClueRuleEnum.NO_COMMUNICATE_RULE.getCode());
            //数据库查询，获取影响到获取线索判断的三个规则
            Map<String, Object> param = new HashMap<>(3);
            param.put("corpid", corpid);
            param.put("ruleTypeIn", ruleTypeIn);
            param.put("del", 0);
            List<ClueRuleEntity> ruleList = clueRuleModel.findEntitys(param);

            Integer advanceTime = getRemindTime(corpid);
            Map<Long, String> clueIdMemoMap = new HashMap<>();
            for(UserEntity user : userList){
                for(ClueRuleEntity rule : ruleList){
                    ICheckClueRule checkRule = checkClueRuleFactory.checkClueRuleFactory(rule.getRuleType());
                    List<RuleClueEntity> notifyClueList = checkRule.getBackClueList(user, rule, clueList, advanceTime);
                    LOG.info("ruleType:" + rule.getRuleType() + " notifyClueList.size():" + notifyClueList.size());

                    if(notifyClueList == null || notifyClueList.isEmpty()){
                        continue;
                    }
                    for (RuleClueEntity clueEntityExt : notifyClueList) {
                        String memo = clueIdMemoMap.get(clueEntityExt.getId());
                        if (StringUtil.isEmpty(memo)) {
                            memo = "";
                        }

                        if(StringUtil.isEmpty(memo)){
                            memo = clueEntityExt.getNotifyMemo();
                        }else{
                            memo += "," + clueEntityExt.getNotifyMemo();
                        }
                        clueIdMemoMap.put(clueEntityExt.getId(), memo);
                    }
                }
            }
            for (RuleClueEntity clue : clueList) {
                Long clueId = clue.getId();
                String memo = clueIdMemoMap.get(clueId);
                updateTagLink(corpid, clueId, memo);
            }
        } catch (Exception e) {
            LOG.error("deleteCluePublicTag error", e);
        }
    }

    private List<RuleClueEntity> formatRuleClue(List<ClueEntityExt> ClueEntityExts) {

        if (ClueEntityExts == null) {
            return null;
        }

        List<RuleClueEntity> clues = new ArrayList<>();
        for (ClueEntityExt clueEntityExt : ClueEntityExts) {
            RuleClueEntity ruleCustomer = new RuleClueEntity();

            Long id = clueEntityExt.getId();
            Long appId = clueEntityExt.getAppId();
            Long menuId = clueEntityExt.getMenuId();
            String corpid = clueEntityExt.getCorpid();

            JSONObject json = JsonHelperUtil.getJSONObject(clueEntityExt.getData());
            String name = json.getString(ClueEnum.COMPANY_NAME.getAttr());
            Long lastConnectTime = json.getLong(ClueEnum.LAST_CONNECT_TIME.getAttr());
            Integer type = json.getInteger(ClueEnum.CLUE_STATUS.getAttr());
            JSONArray jsonArray = json.getJSONArray(ClueEnum.LABEL.getAttr());
            List<Long> labels = null;
            if (CollectionsUtil.isNotEmpty(jsonArray)) {
                labels = JSON.parseArray(jsonArray.toJSONString(), Long.class);
            }

            if (Objects.isNull(labels)) {
                labels = new ArrayList<>();
            }

            ruleCustomer.setId(id);
            ruleCustomer.setAppId(appId);
            ruleCustomer.setMenuId(menuId);
            ruleCustomer.setCorpid(corpid);
            ruleCustomer.setName(name);
            ruleCustomer.setLastConnectTime(lastConnectTime);
            ruleCustomer.setType(type);
            ruleCustomer.setLabels(labels.toString());
            clues.add(ruleCustomer);
        }
        return clues;
    }

    /**
     * @Description: 更新标签
     * @param corpid 公司id
     * @param clueId 线索id
     * @param memo 标签备注
     */
    private void updateTagLink(String corpid, Long clueId, String memo) throws XbbException {
        LOG.info("updateTagLink corpid:" + corpid + " clueId:" + clueId + " memo:" + memo);
        TagLinkEntity tagLink = tagLinkModel.getTagByTagType(corpid, TagTypeEnum.PUBLIC_CLUE_RULE.getCode(), clueId);
        TagEntity returnPublicTag = tagModel.findReturnPublicTag(TagTypeEnum.PUBLIC_CLUE_RULE.getCode());

        if(StringUtil.isEmpty(memo)){
            if (tagLink == null){
                return ;
            }
            List<Long> refIdIn = new ArrayList<>();
            refIdIn.add(clueId);
            //该线索的所有主负责人都不需要退回公海提醒,删除线索标签
            tagLinkModel.deleteTagByTagTypeAndRefIdIn(corpid, TagTypeEnum.PUBLIC_CLUE_RULE.getCode(), refIdIn);
        }else {
            if (memo.indexOf(I18nMessageUtil.getMessage(I18nStringConstant.WILL_RETURN_CUSTOMER_PUBLIC_N)) > -1) {
                memo = memo.replaceFirst(I18nMessageUtil.getMessage(I18nStringConstant.WILL_RETURN_CUSTOMER_PUBLIC_N), I18nMessageUtil.getMessage(I18nStringConstant.WILL_RETURN_CUSTOMER_PUBLIC_1));
            }
            if(tagLink == null){
                tagLink = new TagLinkEntity(corpid, "", returnPublicTag, clueId, XbbRefTypeEnum.CLUE, memo);
            }else{
                tagLink.setMemo(memo);
            }
            tagLinkModel.save(tagLink);
        }
    }

    /**
     * 给用户发送即将退回公海的标签的提醒信息
     *
     * @param user         用户对象
     * @param clueList 符合提醒规则的线索列表
     */
    private void pushTagMessage(UserEntity user, List<RuleClueEntity> clueList, Integer advanceTime) {
        String title = I18nMessageUtil.getMessage(ClueBackPushConstant.CLUE_WILL_BACK_TITLE);
        Map<Long, List<RuleClueEntity>> leftDayMap = clueList.stream().collect(Collectors.groupingBy(RuleClueEntity::getLeftDay));
        for(Map.Entry<Long,List<RuleClueEntity>> entry : leftDayMap.entrySet()){
            String content;
            List<RuleClueEntity> valueList = entry.getValue();
            String clueName = valueList.get(0).getName();
            if (valueList.size() > 1){
                content = String.format(I18nMessageUtil.getMessage(ClueBackPushConstant.CLUE_WILL_BACK_MORE), clueName, entry.getValue().size(), entry.getKey());
            }else {
                content = String.format(I18nMessageUtil.getMessage(ClueBackPushConstant.CLUE_WILL_BACK), clueName, entry.getKey());
            }
            pushMessage(user, valueList, title, content, PushTypeEnum.CLUE_WILL_BACK_PUSH, XbbRefTypeEnum.CLUE);
        }
    }

    /**
     * 为即将退回公海池的线索打上标签
     *
     * @param notifyClueList 即将退回公海池的线索列表
     */
    private void tagReturnPublic(UserEntity user, List<RuleClueEntity> notifyClueList) {

        String userId = user.getUserId();
        String corpid = user.getCorpid();

        TagEntity returnPublicTag = tagModel.findReturnPublicTag(TagTypeEnum.PUBLIC_CLUE_RULE.getCode());

        if (notifyClueList == null || notifyClueList.isEmpty() || returnPublicTag == null) {
            return ;
        }

        Map<Long, TagLinkEntity> clueIdTagLinkMap = getClueIdTagLinkMap(corpid, userId, notifyClueList);
        ArrayList<TagLinkEntity> updateTagLinkList = new ArrayList<>();
        ArrayList<TagLinkEntity> insertTagLinkList = new ArrayList<>();
        for (RuleClueEntity clue : notifyClueList) {
            String memo = clue.getNotifyMemo();
            Long clueId = clue.getId();
            TagLinkEntity tagLink = null;

            if(clueIdTagLinkMap.containsKey(clueId)){
                tagLink = clueIdTagLinkMap.get(clueId);
                tagLink.setMemo(tagLink.getMemo() + "，" + memo);
                updateTagLinkList.add(tagLink);
            }else{
                tagLink = new TagLinkEntity(corpid, "", returnPublicTag, clueId, XbbRefTypeEnum.CLUE, memo);
                insertTagLinkList.add(tagLink);
            }

        }
        if(insertTagLinkList != null && insertTagLinkList.size() != 0){
            tagLinkModel.batchInsert(insertTagLinkList);
        }
        if(updateTagLinkList != null && updateTagLinkList.size() != 0){
            tagLinkModel.batchUpdate(updateTagLinkList);
        }
    }

    /**
     * 获取线索列表notifyClueList中，有tagLink的的map
     *
     * @param corpid
     * @param userId
     * @param notifyClueList 需要提醒的线索列表
     */
    private Map<Long, TagLinkEntity> getClueIdTagLinkMap(
            String corpid, String userId,
            List<RuleClueEntity> notifyClueList) {
        Set<Long> allClueId = new HashSet<>();

        Set<Long> tagLinkClueIdSet = new HashSet<>(16);
        Set<Integer> tagLinkClueIdRedis = null;
        try {
            //这边会被转化成Integer
            tagLinkClueIdRedis = paasRedisHelper.getValue4Set(RedisPrefixConstant.TAG_LINK_CLUE_ID, corpid);
        } catch (Exception e) {
            // ignore
        }
        if(tagLinkClueIdRedis != null){
            for (Integer clueId : tagLinkClueIdRedis) {
                tagLinkClueIdSet.add(clueId.longValue());
            }
        }

        Map<Long, TagLinkEntity> retMap = new HashMap<>(16);

        Set<Long> clueIdSet = new HashSet<>();
        for (RuleClueEntity clue : notifyClueList) {
            clueIdSet.add(clue.getId());
        }
        allClueId.addAll(tagLinkClueIdSet);
        allClueId.addAll(clueIdSet);

        //取交集
        clueIdSet.retainAll(tagLinkClueIdSet);
        List<Long> clueIdIn = new ArrayList<>(clueIdSet);
        if (clueIdIn.size() != 0) {
            List<TagLinkEntity> list = tagLinkModel.getCompanyTagLinksByRefType(corpid, XbbRefTypeEnum.CLUE_PUBLIC.getCode(), clueIdIn);
            for(TagLinkEntity tagLink : list){
                retMap.put(tagLink.getRefId(), tagLink);
            }
        }

        paasRedisHelper.setValue4Set(RedisPrefixConstant.TAG_LINK_CLUE_ID, corpid, allClueId, 2 * 3600);
        return retMap;
    }

    /**
     * 给用户发送退回公海的提醒信息
     *
     * @param user         用户对象
     * @param clueList 符合退回规则的线索列表
     */
    private void pushReturnMessage(UserEntity user, List<RuleClueEntity> clueList, Integer ruleType) {
        String name = clueList.get(0).getName();

        ClueRuleEnum clueRuleEnum = ClueRuleEnum.getByCode(ruleType);
        String ruleName = clueRuleEnum.getName();
        String title = I18nMessageUtil.getMessage(ClueBackPushConstant.CLUE_BACK_TITLE);
        String content = "";
        if (clueList.size() > 1) {
            content = String.format(I18nMessageUtil.getMessage(ClueBackPushConstant.CLUE_BACK_MORE), name, clueList.size(), ruleName);
        } else {
            content = String.format(I18nMessageUtil.getMessage(ClueBackPushConstant.CLUE_BACK), name, ruleName);
        }

        pushMessage(user, clueList, title, content,
                PushTypeEnum.CLUE_BACK_PUSH, XbbRefTypeEnum.CLUE_PUBLIC);
    }

    /**
     * 给用户发送即将退回公海的提醒信息
     *
     * @param user         用户对象
     * @param clueList 符合提醒规则的线索列表
     */
    private void pushMessage(UserEntity user, List<RuleClueEntity> clueList, String title,
                             String content, PushTypeEnum pushTypeEnum, XbbRefTypeEnum xbbRefTypeEnum) {

        if (clueList == null || clueList.isEmpty()) {
            return ;
        }

        RuleClueEntity clue = clueList.get(0);

        Long appId = clue.getAppId();
        Long menuId = clue.getMenuId();

        try {
            String corpid = user.getCorpid();
            List<String> userIds = Arrays.asList(user.getUserId());
            List<Long> refIds = new ArrayList<>();
            for (RuleClueEntity entity : clueList) {
                refIds.add(entity.getId());
            }
            Integer remind = 0;
            Long pushTime = DateTimeUtil.getTodayInt() + 32400;
            ClueEntityExt clueEntityExt = new ClueEntityExt();
            List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.CLUE_BACK_PUBLIC.getCode(), PushTypeEnum.CLUE_BACK_PUBLIC.getSubCode(), user, clueEntityExt);
            pushUserList.addAll(userIds);
            PushRefTypePojo.Options options = new PushRefTypePojo.Options(appId, menuId, refIds, SaasMarkEnum.SAAS.getCode(), xbbRefTypeEnum.getCode());
            MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, refIds, remind,
                    pushTime, title, content, null, options);
            messageService.insertPushData(messageRabbitMqDTO, pushTypeEnum);
        } catch (Exception e) {
            LOG.error("消息入库失败", e);
        }
    }

    private void return2Public(UserEntity user, List<RuleClueEntity> clueList, Integer ruleType) {
        ClueRuleEnum clueRuleEnum = ClueRuleEnum.getByCode(ruleType);
        String ruleName = clueRuleEnum.getName();

        String corpid = user.getCorpid();
        String userName = user.getName();
        Map<String, Object> param;
        List<Long> clueIdList = new ArrayList<>();
        for (RuleClueEntity clue : clueList) {
            clueIdList.add(clue.getId());
            param = userBack2public(clue, user);
            if ((int) param.get("code") == 1) {
                LOG.info("clue.name:clueUserEntity to be del:" + clue);
                try {
                    //日志
                    String opObjectId = clue.getId().toString();

                    String clueName = clue.getName();
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_CLUE_RULE_BACK), ruleName, userName,
                            clueName);
                    // + clue.getPhoneStr()

                    mongoLogHelp.buildLog(corpid, PaasConstant.SYS_USER_ID, I18nMessageUtil.getMessage(PaasConstant.SYS_OPERATING), OperateModuleTypeEnum.OpenSeaRules, OperateTypeEnum.RETURN_TO_PUBLIC, opObjectId, clueName, memo, null);
                } catch (Exception e) {
                    LOG.error("日志记录失败", e);
                }
            }
        }
        //评分计算（ 线索退回公海池）。捞取，退回公海池，移交，负责团队变跟，这些只修改分配时间的不需要触发评分
//        try {
//            scoreCalculateService.asyncUpdateBatchDataScore(XbbRefTypeEnum.CLUE,corpid,clueList.stream().map(item->item.getId()).collect(Collectors.toList()));
//        }catch (Exception e){
//            LOG.error("return2Public 客户退户公海池，异步计算评分异常,原因-{}-",e.getMessage());
//        }
        // 删除已经退回公海池线索的"即将退回公海池"的标签
        tagLinkModel.deleteTagByTagTypeAndRefIdIn(user.getCorpid(), TagTypeEnum.PUBLIC_CLUE_RULE.getCode(), clueIdList);
    }

    private Map<String, Object> userBack2public(RuleClueEntity clue, UserEntity user) {
        String userId = user.getUserId();
        String corpid = user.getCorpid();
        Long clueId = clue.getId();
        Map<String, Object> retMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("clueId", clueId);
        param.put("userId", userId);
        param.put("corpid", corpid);
        param.put("del", 0);
        Integer count = clueUserModel.getEntitysCount(param);
        if (Objects.equals(count, 0)) {
            retMap.put("code", UserTeamErrorCodeEnum.API_ERROR_390004.getCode());
            retMap.put("msg", UserTeamErrorCodeEnum.API_ERROR_390004.getMsg());
            return retMap;
        }

        List<Long> clueIdList = new ArrayList<>();
        clueIdList.add(clueId);

        boolean flag;
        try {
            flag = userTeamService.updateClueTeam(user, clueIdList, UpdateCustomerTeamScenesEnum.PUBLIC_RULE_SCRIPT,clue.getFormId(),SaasMarkEnum.SAAS.getCode(),XbbRefTypeEnum.CLUE.getCode(), DistributorMarkEnum.OTHER.getCode(),null);
        } catch (XbbException e) {
            LOG.error("updateClueTeam error", e);
            flag = false;
        }
        if (flag) {
            retMap.put("code", ErrorCodeEnum.API_SUCCESS.getCode());
            retMap.put("msg", ErrorCodeEnum.API_SUCCESS.getMsg());
        } else {
            retMap.put("code", ErrorCodeEnum.API_FAIL.getCode());
            retMap.put("msg", ErrorCodeEnum.API_FAIL.getMsg());
        }
        return retMap;
    }

    /**
     * 用于移除已退回的线索
     *
     * @param clueList
     * @param backClueList
     */
    private void remove(List<RuleClueEntity> clueList, List<RuleClueEntity> backClueList) {
        if (backClueList == null || backClueList.isEmpty()) {
            return;
        }

        //需要移除的线索id集合
        Set<Long> clueIdSet = new HashSet<>();
        for (RuleClueEntity clue : backClueList) {
            clueIdSet.add(clue.getId());
        }

        Iterator<RuleClueEntity> it = clueList.iterator();
        while (it.hasNext()) {
            RuleClueEntity clue = it.next();
            if (clueIdSet.contains(clue.getId())) {
                it.remove();
            }
        }

    }

    /**
     * 是否推送给主负责人
     *
     * @param corpid
     */
    private boolean getIsPushMain(String corpid) {
        CluePushSet cluePushSet = new CluePushSet();
        PushSetEntity pushSetEntity = cluePushSet.getPushSet(corpid, PushTypeEnum.CLUE_BACK_PUBLIC.getSubCode(), pushSetModel);
        boolean isPushMain = false;
        if (Objects.equals(pushSetEntity.getEnable(), 1)) {
            String pushObjectString = pushSetEntity.getPushObject();
            JSONObject pushObject = JsonHelperUtil.parseObject(pushObjectString);
            String typeString = pushObject.getString("type");
            JSONArray typeJsonArray = JsonHelperUtil.parseArray(typeString);
            for (Object object : typeJsonArray) {
                JSONObject jsonObject = (JSONObject) object;
                Integer enable = jsonObject.getInteger("enable");
                if (Objects.equals(enable, 1)) {
                    String alias = jsonObject.getString("alias");
                    if (Objects.equals(alias, PushObjectTypeEnum.MAINUSER.getAlias())) {
                        isPushMain = true;
                    }
                }
            }
        } else {
            isPushMain = false;
        }
        return isPushMain;
    }

    /**
     * 获取脚本相关的公海规则 无新建跟进线索规则  无新建机会线索规则  无新建合同线索规则 最大拥有线索数规则
     *
     */
    private List<ClueRuleEntity> getRuleRelatedScript(String corpid) {
        //获取公司所有的相关公海规则   无新建跟进线索规则  无新建机会线索规则  无新建合同线索规则 最大拥有线索数规则
        List<Integer> ruleTypeIn = new ArrayList<>();
        ruleTypeIn.add(ClueRuleEnum.NO_COMMUNICATE_RULE.getCode());
        ruleTypeIn.add(ClueRuleEnum.MAX_CLUE_NUM_RULE.getCode());

        //数据库查询，获取影响到获取线索判断的四个规则
        Map<String, Object> param = new HashMap<>(3);
        param.put("corpid", corpid);
        param.put("ruleTypeIn", ruleTypeIn);
        param.put("status", 1);
        param.put("del", 0);
        return clueRuleModel.findEntitys(param);
    }

    private Integer getRemindTime(String corpid) {
        Integer remindTime = 3;
        try {
            CompanyConfigEntity companyConfig = companyConfigModel.getConfigEntity(corpid,
                    CompanyConfigEnum.CLUE_PUBLIC_RULE_REMIND_TIME.getAlias());
            if (companyConfig != null) {
                remindTime = StringUtil.toInt(companyConfig.getConfigValue(), 3);
            }
        } catch (Exception e) {
            LOG.error("getRemindTime异常，corpid=" + corpid, e);
        }
        return remindTime;
    }

    /**
     * 【web】公海规则设置选择员工
     *
     * @param clueRuleUserListDTO 公海规则设置选择员工入参
     * @return Integer
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CustomerRuleUserListVO> userList(CustomerRuleUserListDTO clueRuleUserListDTO) throws XbbException {
        List<UserEntity> userList = getAllUserListLimit500(clueRuleUserListDTO.getCorpid(),
                clueRuleUserListDTO.getUserNameLike(), null);

        CustomerRuleUserListVO userArray = new CustomerRuleUserListVO();
        List<CustomerUserPojo> userPojoList = new ArrayList<>();
        for (UserEntity user : userList) {
            CustomerUserPojo clueUserPojo = new CustomerUserPojo();
            clueUserPojo.setUserId(user.getUserId());
            clueUserPojo.setName(user.getName());
            userPojoList.add(clueUserPojo);
        }
        userArray.setUserArray(userPojoList);
        return new XbbResponse<>(userArray);
    }

    @Override
    @Async(value = "returnPublicClueThreadPool")
    public XbbResponse<BaseVO> returnClue2PublicAsync(ReturnCustomer2PublicAsyncDTO returnCustomer2PublicAsyncDTO) throws XbbException {
        String[] split = returnCustomer2PublicAsyncDTO.getLocale().split("_");
        LocaleContextHolder.setLocale(new Locale(split[0], split[1]));
        BaseVO returnClue2PublicVO = new BaseVO();
        String singleCorpid = returnCustomer2PublicAsyncDTO.getCorpid();

        boolean back = returnCustomer2PublicAsyncDTO.getBack();

        boolean notify = returnCustomer2PublicAsyncDTO.getNotify();

        List<String> corpids = returnCustomer2PublicAsyncDTO.getCorpids();
        //boolean isGrayEnvironmentEnable = sysEnvHelp.isGrayEnvironmentEnable();

        List<CompanyEntity> companyList;
        if (StringUtil.isNotEmpty(singleCorpid)) {
            //灰度判断逻辑去掉
//            if (sysEnvHelp.isGrayEnvironment()) {
//                if (!isGrayEnvironmentEnable) {
//                    return new XbbResponse<>(returnClue2PublicVO);
//                }
//                if (!sysEnvHelp.checkIsCrayCompany(singleCorpid)) {
//                    return new XbbResponse<>(returnClue2PublicVO);
//                }
//            } else {
//                if (isGrayEnvironmentEnable) {
//                    if (sysEnvHelp.checkIsCrayCompany(singleCorpid)) {
//                        return new XbbResponse<>(returnClue2PublicVO);
//                    }
//                }
//            }
            if (commonHelp.isCluePublicPoolSeniorModel((singleCorpid))){
                LOG.warn("该公司开启了线索公海高级模式，停止定时任务！");
                return new XbbResponse<>(returnClue2PublicVO);
            }
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", 0);
            params.put("corpid", singleCorpid);
            params.put("start", 0);
            params.put("pageNum", 1);
            companyList = companyModel.findEntitys(params);
            if (companyList.size() > 0) {
                backToPublic(singleCorpid, notify, back);
                LOG.info("公司（ID=" + companyList.get(0).getCorpid() + "）：退回公海池任务执行完成！");
                LOG.info("returnClue_finished:" + companyList.get(0).getCorpid());
            }
        } else {
            //去除开启了客户公海高级模式的公司
            publicSeniorRuleHelp.removeCorpidsByModel(corpids,false,XbbRefTypeEnum.CLUE.getCode());

            for (String corpid : corpids) {
                   //灰度判断逻辑去掉
//                if (sysEnvHelp.isGrayEnvironment()) {
//                    if (!isGrayEnvironmentEnable) {
//                        continue;
//                    }
//                    if (!sysEnvHelp.checkIsCrayCompany(corpid)) {
//                        continue;
//                    }
//                } else {
//                    if (isGrayEnvironmentEnable) {
//                        if (sysEnvHelp.checkIsCrayCompany(corpid)) {
//                            continue;
//                        }
//                    }
//                }

                backToPublic(corpid, notify, back);
                LOG.info("公司（ID=" + corpid + "）：退回公海池任务执行完成！");
                LOG.info("returnClue_finished:" + corpid);
            }
        }
        return new XbbResponse<>(returnClue2PublicVO);
    }

    /**
     * 公海池规则处理
     *
     * @param ruleType
     * @param corpid
     * @return
     * @throws XbbException
     */
    private ClueRuleDetailVO detail(Integer ruleType, String corpid) throws XbbException {
        ClueRuleDetailVO clueRuleDetailVO = new ClueRuleDetailVO();
        ClueRuleEntity rule = clueRuleModel.getByRuleType(ruleType, corpid);
        Integer status = 0;
        if (rule != null) {
            status = rule.getStatus();
        }
        IOperateClueRuleValue operateRuleValue = OperateClueRuleValueFactory.operateRuleValueFactory(ruleType);
        Object ruleObject = operateRuleValue.toObject(rule);

        List<String> specialUserList = operateRuleValue.getAllSpecialUser(ruleObject);
        // 规则用户格式封装
        if(ruleObject != null){
            JSONArray userArr ;
            if(!Objects.equals(ruleType, ClueRuleEnum.PRE_PRINCIPAL_RULE.getCode()) &&
                    !Objects.equals(ruleType, ClueRuleEnum.GAIN_RATE_RULE.getCode())){
                userArr = ((JSONObject)ruleObject).getJSONArray("restrict");
            } else {
                userArr = (JSONArray) ruleObject;
            }
            Integer type = null;
            if (Objects.equals(ruleType, ClueRuleEnum.NO_COMMUNICATE_RULE.getCode()) ||
                    Objects.equals(ruleType, ClueRuleEnum.MAX_CLUE_NUM_RULE.getCode())) {
                String label = ((JSONObject) ruleObject).getString("label");
                type = ((JSONObject) ruleObject).getInteger("type");
                List<Long> labelIds = JSONArray.parseArray(label, Long.class);
                if (CollectionsUtil.isNotEmpty(labelIds)) {
                    Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    param.put("corpid", corpid);
                    param.put("del", DelEnum.NORMAL.getDel());
                    param.put("idIn", labelIds);
                    param.put("columns", "id,lable_name,form_id,lable_color");
                    List<LabelEntity> byLabelIds = labelModel.findEntitys(param);

                    Set<Long> formIds = new HashSet<>();
                    Map<Long, LabelEntity> labelEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    for (LabelEntity entity : byLabelIds) {
                        labelEntityMap.put(entity.getId(), entity);
                        formIds.add(entity.getFormId());
                    }

                    Map<Long, String> formIdAndName = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    if (CollectionsUtil.isNotEmpty(formIds)) {
                        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        map.put("corpid", corpid);
                        map.put("del", DelEnum.NORMAL.getDel());
                        map.put("idIn", formIds);
                        List<PaasFormEntityExt> entitys = paasFormModel.findEntitys(map);
                        for (PaasFormEntityExt entity : entitys) {
                            formIdAndName.put(entity.getId(), entity.getName());
                        }
                    }
                    List<PublicRuleLabelPojo> ruleLabelPojos = new ArrayList<>();
                    for (Long id : labelIds) {
                        LabelEntity entity = labelEntityMap.get(id);
                        if (Objects.isNull(entity)) {
                            continue;
                        }
                        Long formId = entity.getFormId();
                        String name = entity.getName();
                        if (formIdAndName.containsKey(formId)) {
                            String formName = formIdAndName.get(formId);
                            // 名称一样的，需要在给标签名称改为“表单名称/标签名称”
                            if (StringUtil.isNotEmpty(formName)) {
                                name = formName + "/" + name;
                                entity.setName(name);
                            }
                        }
                        PublicRuleLabelPojo ruleLabelPojo = new PublicRuleLabelPojo();
                        BeanUtil.copyProperties(entity, ruleLabelPojo, true);
                        ruleLabelPojos.add(ruleLabelPojo);
                    }

                    ((JSONObject) ruleObject).put("label", ruleLabelPojos);
                }
            }
            if(!userArr.isEmpty()){
                for(Object userObj : userArr){
                    JSONArray specialUserArr = ((JSONObject)userObj).getJSONArray("users");
                    if(specialUserArr != null){
                        List<String> idList = JSON.parseArray(specialUserArr.toJSONString(), String.class);
                        List<UserEntity> getByUserId = userModel.getByUserId(idList, corpid);
                        List<OptionalRangeEntity> optionalRangeEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        for(UserEntity userEntity : getByUserId){
                            OptionalRangeEntity optionalRangeEntity = new OptionalRangeEntity();
                            optionalRangeEntity.setId(userEntity.getUserId());
                            optionalRangeEntity.setName(userEntity.getName());
                            optionalRangeEntity.setEditable(1);
                            optionalRangeEntity.setProperty(OptionalRangeEnum.USER.getValue());
                            optionalRangeEntityList.add(optionalRangeEntity);
                        }
                        JSONArray deptArr = ((JSONObject)userObj).getJSONArray("depts");
                        if(deptArr != null){
                            // 因为前端回显人员和部门是用同一个组件，所以这里部门也加在人员一起
                            List<Long> deptIds = JSON.parseArray(deptArr.toJSONString(), Long.class);
                            List<DepartmentEntity> deptEntitys = departmentModel.getByDepIdIn(corpid, deptIds);
                            for(DepartmentEntity departmentEntity : deptEntitys){
                                OptionalRangeEntity optionalRangeEntity = new OptionalRangeEntity();
                                optionalRangeEntity.setId(departmentEntity.getId().toString());
                                optionalRangeEntity.setName(departmentEntity.getName());
                                optionalRangeEntity.setEditable(1);
                                optionalRangeEntity.setProperty(OptionalRangeEnum.DEPT.getValue());
                                optionalRangeEntityList.add(optionalRangeEntity);
                            }
                        }
                        JSONArray roleArr = ((JSONObject)userObj).getJSONArray("roles");
                        if(roleArr != null){
                            // 因为前端回显人员和部门是用同一个组件，所以这里部门也加在人员一起
                            List<Integer> roleIds = JSON.parseArray(roleArr.toJSONString(), Integer.class);
                            List<RoleEntity> roleEntities = roleModel.getByRoleIdIn(corpid, roleIds);
                            for(RoleEntity roleEntity : roleEntities){
                                OptionalRangeEntity optionalRangeEntity = new OptionalRangeEntity();
                                optionalRangeEntity.setId(roleEntity.getId().toString());
                                optionalRangeEntity.setName(roleEntity.getRoleName());
                                optionalRangeEntity.setEditable(1);
                                optionalRangeEntity.setProperty(OptionalRangeEnum.ROLE.getValue());
                                optionalRangeEntityList.add(optionalRangeEntity);
                            }
                        }
                        ((JSONObject) userObj).put("users", optionalRangeEntityList);
                    }
                    if (Objects.equals(type, ChildClueRuleEnum.CLUE_LABEL.getCode())) {
                        JSONArray array = ((JSONObject)userObj).getJSONArray("array");
                        for (Object obj : array) {
                            String key;
                            try {
                                key = ((JSONObject)obj).getString("key");
                            } catch (Exception e) {
                                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
                            }
                            List<Long> labelIds = JSONArray.parseArray(key, Long.class);
                            if (CollectionsUtil.isNotEmpty(labelIds)) {
                                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                param.put("corpid", corpid);
                                param.put("del", DelEnum.NORMAL.getDel());
                                param.put("idIn", labelIds);
                                param.put("columns", "id,lable_name,form_id,lable_color");
                                List<LabelEntity> byLabelIds = labelModel.findEntitys(param);

                                Set<Long> formIds = new HashSet<>();
                                Map<Long, LabelEntity> labelEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                for (LabelEntity entity : byLabelIds) {
                                    labelEntityMap.put(entity.getId(), entity);
                                    formIds.add(entity.getFormId());
                                }

                                Map<Long, String> formIdAndName = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                if (CollectionsUtil.isNotEmpty(formIds)) {
                                    Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                    map.put("corpid", corpid);
                                    map.put("del", DelEnum.NORMAL.getDel());
                                    map.put("idIn", formIds);
                                    List<PaasFormEntityExt> entitys = paasFormModel.findEntitys(map);
                                    for (PaasFormEntityExt entity : entitys) {
                                        formIdAndName.put(entity.getId(), entity.getName());
                                    }
                                }
                                JSONArray jsonArray = new JSONArray();
                                for (Long id : labelIds) {
                                    LabelEntity entity = labelEntityMap.get(id);
                                    if (Objects.isNull(entity)) {
                                        continue;
                                    }
                                    Long formId = entity.getFormId();
                                    String name = entity.getName();
                                    if (formIdAndName.containsKey(formId)) {
                                        String formName = formIdAndName.get(formId);
                                        // 名称一样的，需要在给标签名称改为“表单名称/标签名称”
                                        if (StringUtil.isNotEmpty(formName)) {
                                            name = formName + "/" + name;
                                            entity.setName(name);
                                        }
                                    }
                                    JSONObject jsonObject = new JSONObject();
                                    jsonObject.put("id", id);
                                    jsonObject.put("name", name);
                                    jsonObject.put("formId", formId);
                                    jsonObject.put("color", entity.getColor());
                                    jsonArray.add(jsonObject);
                                }
                                ((JSONObject)obj).put("key", jsonArray.toJSONString());
                            }
                        }
                    }
                }
            }

            clueRuleDetailVO.setRuleValue(ruleObject);
        }else {
            //新公司初始化 ruleValue为null
            Object ruleValue = publicSeniorRuleHelp.initPublicRule(XbbRefTypeEnum.CLUE.getCode(),ruleType,false);
            clueRuleDetailVO.setRuleValue(ruleValue);
        }
        clueRuleDetailVO.setStatus(status);
        return clueRuleDetailVO;
    }

    /**
     * 公海规则设置选择员工
     *
     * @param corpid       公司id
     * @param userNameLike 员工姓名模糊查询
     * @version v1.0
     * @since v1.0
     */
    public List<UserEntity> getAllUserListLimit500(String corpid, String userNameLike, List<String> userIdIn) {
        if (userIdIn != null && userIdIn.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> param = new HashMap<>(16);
        param.put("columns", "id,department,avatar,user_id,name,role_ids,is_boss");
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("nameLike", userNameLike);
        param.put("userIdIn", userIdIn);

        // 当不指定员工时才分页，否则当userIdIn.size()大于分页数时，会有部分数据搜不到
        if (userIdIn == null) {
            param.put("start", 0);
            // 最多查询100个
            param.put("pageNum", 100);
        }
        List<UserEntity> userList = userModel.findEntitys(param);
        return userList;
    }


    /**
     * @param ruleType 规则类型
     * @return
     * @Description: 获取规则的子类型选项
     */
    private List<ClueRuleTypePojo> getChildTypeList(Integer ruleType) {
        List<ClueRuleTypePojo> rulePojoList = new ArrayList<>();
        if (ruleType == null) {
            return new ArrayList<>();
        }
        ClueRuleEnum clueRule = ClueRuleEnum.getByCode(ruleType);
        switch (clueRule) {
            case NO_COMMUNICATE_RULE:
            case MAX_CLUE_NUM_RULE:
                rulePojoList = getChildTypeList();
                break;
            default:
                break;
        }
        return rulePojoList;
    }

    /**
     * 规则的子类型选项
     */
    public static List<ClueRuleTypePojo> getChildTypeList() {
        List<ClueRuleTypePojo> typeList = new ArrayList<>();
        for (ClueChildTypeEnum type : ClueChildTypeEnum.values()) {
            if (type == ClueChildTypeEnum.UNKNOWN) {
                continue;
            }
            ClueRuleTypePojo clueRuleTypePojo = new ClueRuleTypePojo();
            clueRuleTypePojo.setKey(type.getCode());
            clueRuleTypePojo.setValue(type.getName());
            typeList.add(clueRuleTypePojo);
        }
        return typeList;
    }

    /**
     * 公海池规则数据封装插入或更新
     *
     * @param corpid              公司id
     * @param clueRuleSaveDTO
     * @return
     * @throws XbbException
     */
    private Integer save(String corpid, ClueRuleSaveDTO clueRuleSaveDTO) throws XbbException {

        IOperateClueRuleValue operateRuleValue = OperateClueRuleValueFactory.operateRuleValueFactory(clueRuleSaveDTO.getRuleType());
        String ruleValue = null;
        RuleSavePojo ruleSavePojo = clueRuleSaveDTO.getRuleValue();
        if (ruleSavePojo != null) {
            String getRuleValue;
            try {
                getRuleValue = JSON.toJSONString(ruleSavePojo);
            } catch (Exception e) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
            }
            operateRuleValue.verify(getRuleValue);
            // 特殊处理
            if(getRuleValue != null){
                JSONObject ruleValueObject = JSONArray.parseObject(getRuleValue);
                List<RestrictPojo> restrictList = ruleSavePojo.getRestrict();
                if(!restrictList.isEmpty()){
                    JSONArray userArr = JSONArray.parseArray(JSON.toJSONString(restrictList));
                    if(!userArr.isEmpty()){
                        for(Object userObj : userArr){
                            JSONArray specialUserArr = ((JSONObject)userObj).getJSONArray("users");
                            if(specialUserArr != null){
                                List<String> users = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                List<String> depts = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                List<String> roles = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                specialUserArr.forEach(item -> {
                                    String property = ((JSONObject) item).getString("property");
                                    String id = ((JSONObject) item).getString("id");
                                    if (Objects.equals(property, OptionalRangeEnum.USER.getValue())) {
                                        users.add(id);
                                    } else if (Objects.equals(property, OptionalRangeEnum.DEPT.getValue())) {
                                        depts.add(id);
                                    } else if (Objects.equals(property, OptionalRangeEnum.ROLE.getValue())) {
                                        roles.add(id);
                                    }
                                });
                                ((JSONObject) userObj).put("users", users);
                                if (!depts.isEmpty()) {
                                    // 因为上面的人员是直接存数组的，所以部门这里为了区分只能是另放在depts里面
                                    ((JSONObject) userObj).put("depts", depts);
                                }
                                if (!roles.isEmpty()) {
                                    // 因为上面的人员是直接存数组的，所以角色这里为了区分只能是另放在roles里面
                                    ((JSONObject) userObj).put("roles", roles);
                                }
                            }
                        }
                    }
                    JSONArray restrictJsonArray = ruleValueObject.getJSONArray("restrict");
                    if(restrictJsonArray != null){
                        for(Object restrictObj : restrictJsonArray){
                            JSONArray array = ((JSONObject)restrictObj).getJSONArray("users");
                            if(array != null){
                                ruleValueObject.put("restrict", userArr);
                            }
                        }
                    }
                }
                getRuleValue = ruleValueObject.toJSONString();
            }
            ruleValue = getRuleValue;
        }
        // 5.前负责人规则6.捞取频次限制
        List<LeadOrFrePojo> leadOrFre = clueRuleSaveDTO.getLeadOrFre();
        if (leadOrFre != null) {
            String getLeadOrFre;
            try {
                getLeadOrFre = JSONArray.toJSONString(leadOrFre);
            } catch (Exception e) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
            }
            operateRuleValue.verify(getLeadOrFre);

            if(getLeadOrFre != null){
                JSONArray userArr = JSONArray.parseArray(getLeadOrFre);
                if(!userArr.isEmpty()){
                    for(Object userObj : userArr){
                        JSONArray specialUserArr = ((JSONObject)userObj).getJSONArray("users");
                        if(specialUserArr != null){
                            List<String> users = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            List<String> depts = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            List<String> roles = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            specialUserArr.forEach(item -> {
                                String property = ((JSONObject) item).getString("property");
                                String id = ((JSONObject) item).getString("id");
                                if (Objects.equals(property, OptionalRangeEnum.USER.getValue())) {
                                    users.add(id);
                                } else if (Objects.equals(property, OptionalRangeEnum.DEPT.getValue())) {
                                    depts.add(id);
                                } else if (Objects.equals(property, OptionalRangeEnum.ROLE.getValue())) {
                                    roles.add(id);
                                }
                            });
                            ((JSONObject) userObj).put("users", users);
                            if (!depts.isEmpty()) {
                                // 因为上面的人员是直接存数组的，所以部门这里为了区分只能是另放在depts里面
                                ((JSONObject) userObj).put("depts", depts);
                            }
                            if (!roles.isEmpty()) {
                                // 因为上面的人员是直接存数组的，所以角色这里为了区分只能是另放在roles里面
                                ((JSONObject) userObj).put("roles", roles);
                            }
                        }
                    }
                }
                getLeadOrFre = userArr.toJSONString();
            }

            ruleValue = getLeadOrFre;
        }

        Integer ruleType = clueRuleSaveDTO.getRuleType();
        Integer status = clueRuleSaveDTO.getStatus();

        ClueRuleEntity ruleEntity = clueRuleModel.getByRuleType(ruleType, corpid);

        if (ruleEntity == null) {
            ruleEntity = new ClueRuleEntity();
            ruleEntity.setCorpid(corpid);
            ruleEntity.setRuleType(ruleType);
            ruleEntity.setDel(0);
        }
        ruleEntity.setStatus(status);
        ruleEntity.setRuleValue(ruleValue);

        Integer saveId;
        try {
            saveId = clueRuleModel.save(ruleEntity);
        } catch (Exception e) {
            LOG.error("公海池规则数据插入或更新失败，corpid=" + corpid, e);
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218004);
        }
        return saveId;
    }

    /**
     * 公海池规则保存时的日志保存
     *
     * @param corpid    公司ID
     * @param oldEntity
     * @param newEntity
     * @throws XbbException
     */
    private void saveLog(String corpid, ClueRuleEntity oldEntity, ClueRuleEntity newEntity,
                         ClueRuleSaveDTO clueRuleSaveDTO) throws XbbException {
        if (newEntity == null) {
            LOG.error("新公海规则为空");
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218005);
        }
        // 数据字典项：获取线索状态
        Map<String, String> clueStatusMap = ClueStatusEnum.getCodeAndNameMap();

        // 公海池规则
        Integer ruleType = newEntity.getRuleType();

        IOperateClueRuleValue operateRuleValue = OperateClueRuleValueFactory.operateRuleValueFactory(ruleType);
        Integer oldStatus = operateRuleValue.getStatus(oldEntity);
        JSONArray oldCustomerStatusArray = operateRuleValue.getClueStatus(oldEntity);
        Integer oldType = operateRuleValue.getType(oldEntity);
        JSONArray oldRestrict = operateRuleValue.getRestrict(oldEntity);
        List<Long> oldLabelIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(oldEntity != null){
            oldLabelIds = operateRuleValue.getClueLabelIds(oldEntity.getRuleValue());
        }
        Integer newStatus = operateRuleValue.getStatus(newEntity);
        JSONArray newClueStatusArray = operateRuleValue.getClueStatus(newEntity);
        Integer newType = operateRuleValue.getType(newEntity);
        JSONArray newRestrict = operateRuleValue.getRestrict(newEntity);
        List<Long> newLabelIds = operateRuleValue.getClueLabelIds(newEntity.getRuleValue());

        JSONObject oldBackRule = null;
        JSONObject newBackRule = null;
        if (Objects.equals(ruleType, ClueRuleEnum.MAX_CLUE_NUM_RULE.getCode())) {
            oldBackRule = ((OperateMaxClueNumRuleValue) operateRuleValue).getBackRule(oldEntity);
            newBackRule = ((OperateMaxClueNumRuleValue) operateRuleValue).getBackRule(newEntity);
        }

        // 日志备注拼接
        memo(corpid, newEntity, oldStatus, oldCustomerStatusArray, oldType, oldRestrict,oldLabelIds,
                newStatus, newClueStatusArray, newType, newRestrict, newLabelIds, oldBackRule,
                newBackRule, ruleType, clueStatusMap, clueRuleSaveDTO);
    }

    /**
     * 日志备注字段的拼接
     *
     * @param corpid                 公司ID
     * @param newEntity              线索公海池规则实体
     * @param oldStatus              老状态
     * @param oldCustomerStatusArray 老线索状态list
     * @param oldType                老类型
     * @param oldRestrict            老限制条件
     * @param newStatus              新状态
     * @param newClueStatusArray 新线索状态list
     * @param newType                新类型
     * @param newRestrict            新限制条件
     * @param oldBackRule            老退回规则
     * @param newBackRule            新退回规则
     * @param ruleType               1.跟进时间 2.有无机会 3.有无合同 4.总数限制
     * @param clueStatusMap      数据字典
     * @param clueRuleSaveDTO    公海池保存规则入参
     * @return 日志备注字段的拼接字符串
     */
    private void memo(String corpid, ClueRuleEntity newEntity, Integer oldStatus,
                      JSONArray oldCustomerStatusArray, Integer oldType, JSONArray oldRestrict, List<Long> oldLabelIds,
                      Integer newStatus, JSONArray newClueStatusArray, Integer newType, JSONArray newRestrict, List<Long> newLabelIds,
                      JSONObject oldBackRule, JSONObject newBackRule, Integer ruleType, Map<String, String> clueStatusMap, ClueRuleSaveDTO clueRuleSaveDTO) throws XbbException {
        String userId = clueRuleSaveDTO.getUserId();
        // 登录用户
        String loginUserName = clueRuleSaveDTO.getLoginUserName();
        // 公海池规则名称
        String opObjectName = ClueRuleEnum.getByCode(ruleType).getName();
        String defaultMemo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_CLUE_RULE), loginUserName, opObjectName);

        OperateTypeEnum operateTypeEnum = OperateTypeEnum.EDIT;
        // 是否启用或关闭某种规则
        String isOpenRule = null;
        if (!Objects.equals(newStatus, oldStatus)) {
            if (Objects.equals(newStatus, 0)) {
                operateTypeEnum = OperateTypeEnum.CLOSE;
                // 操作类型标识
                isOpenRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_CLOSE_CLUE_RULE), opObjectName);
            } else {
                operateTypeEnum = OperateTypeEnum.ENABLE;
                // 操作类型标识
                isOpenRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_OPEN_CLUE_RULE), opObjectName);
            }
        }
        // 标签变化
        String changLabel = null;
        if(CollectionUtils.isNotEmpty(oldLabelIds) || CollectionUtils.isNotEmpty(newLabelIds)) {
            List<String> labelListOld = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<String> labelIdListNew = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            String oldStr = "";
            String newStr = "";
            if(oldLabelIds.size() > 0){
                List<LabelEntity> labelEntityList = labelModel.getByLabelIds(oldLabelIds, corpid);
                labelEntityList.forEach(labelEntity -> labelListOld.add(labelEntity.getName()));
                oldStr = StringUtils.join(labelListOld, "，");
            }
            if(newLabelIds.size() > 0){
                List<LabelEntity> labelEntityList = labelModel.getByLabelIds(newLabelIds, corpid);
                labelEntityList.forEach(labelEntity -> labelIdListNew.add(labelEntity.getName()));
                newStr = StringUtils.join(labelIdListNew, "，");
            }
            if(oldStr != "" || newStr != ""){
                changLabel = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_LABEL_RULE), oldStr, newStr);
            }
        }

        // 设置是不包含的线索状态
        String notStatusRule = null;
        if (!Objects.equals(newClueStatusArray, oldCustomerStatusArray)) {
            if (newClueStatusArray.size() == 0) {
                notStatusRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_NOT_CLUE_STATUS_RULE), opObjectName);
            } else {
                StringBuilder statusStr = new StringBuilder();
                for (Object statusObject : newClueStatusArray) {
                    String statusInt = (String) statusObject;
                    statusStr.append(" " + clueStatusMap.get(statusInt));
                }
                notStatusRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_CLUE_STATUS_RULE), opObjectName, statusStr.toString());
            }
        }
        // 编辑设置
        String updateRule = null;
        if (!Objects.equals(newType, oldType)) {
            ClueChildTypeEnum childCustomerRule = ClueChildTypeEnum.getChildTypeByCode(newType);
            if (childCustomerRule != ClueChildTypeEnum.UNKNOWN) {
                updateRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_NEW_CUSTOMER_RULE), childCustomerRule.getName());
            }
        }
        // 编辑了数值设置
        String setRule = null;
        if (!Objects.equals(newRestrict, oldRestrict)) {
            setRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_DATE_SET));
        }
        // 编辑了超过最大线索数退回规则
        String maxBackRule = null;
        if (!Objects.equals(newBackRule, oldBackRule)) {
            maxBackRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_MAX_CLUE_BACK_RULE));
        }
        StringBuilder memoStr = new StringBuilder();
        memoStr.append(defaultMemo);
        if(isOpenRule != null){
            memoStr.append(isOpenRule);
        }
        if(notStatusRule != null){
            memoStr.append(notStatusRule);
        }
        if(updateRule != null){
            memoStr.append(updateRule);
        }
        if(setRule != null){
            memoStr.append(setRule);
        }
        if(maxBackRule != null){
            memoStr.append(maxBackRule);
        }
        if(changLabel != null){
            memoStr.append(changLabel);
        }

        mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.OpenSeaRules, operateTypeEnum,
                newEntity.getId().toString(), OperateModuleTypeEnum.OpenSeaRules.getName(), memoStr.toString(), clueRuleSaveDTO.getHttpHeader());
    }

    /**
     * 公司配置保存公海池退回时间
     *
     * @param corpid 公司ID
     * @param day
     * @throws XbbException
     */
    private Integer saveRemindTime(String corpid, Integer day) throws XbbException {
        String configValue = String.valueOf(day);
        CompanyConfigEntity companyConfig = companyConfigModel.initConfigEntity(corpid,
                CompanyConfigEnum.CLUE_PUBLIC_RULE_REMIND_TIME.getAlias());

        companyConfig.setConfigValue(configValue);
        companyConfig.setUpdateTime(DateTimeUtil.getInt());
        Integer id;
        try {
            id = companyConfigModel.update(companyConfig);
        } catch (Exception e) {
            LOG.error("公司配置保存公海池退回时间失败，corpid=" + corpid, e);
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218006);
        }
        return id;
    }



}
